/*
 * Copyright 2007 The semap project development team.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Created by myn at 06.08.2007 12:40:20.
 *
 * ContactServ Application class.
 *
 * $Id$
 */
package com.google.code.contactserv;

import com.google.code.contactserv.common.makers.PropertyPairsMaker;
import com.google.code.contactserv.model.Contact;
import com.google.code.contactserv.service.ContactService;
import com.google.code.contactserv.service.ContactServiceImpl;
import org.apache.commons.cli.*;

import java.util.List;

public class ContactServ {

    // constants
    public static final String DEF_FILENAME = "contactserv.rdf";

    private String inputFileName = DEF_FILENAME;
    private String command = null;
    private String helpCommand = null;
    private CommandLine line = null;
    private ContactService srv = ContactServiceImpl.getInstance();

    /**
     * @param str string command
     * @return true where string is command
     */
    protected static boolean isCommand(String str) {
        if (str.equals("find")) {
            return true;
        } else if (str.equals("get")) {
            return true;
        } else if (str.equals("add")) {
            return true;
        } else if (str.equals("update")) {
            return true;
        } else if (str.equals("remove")) {
            return true;
        } else if (str.equals("help")) {
            return true;
        } else {
            return false;
        }
    }

    public String getCommand() {
        return command;
    }

    public String getHelpCommand() {
        return helpCommand;
    }

    /**
     * Setup current command. In case the current command is "help"
     * subsequent call initializes command requested for help
     *
     * @param str command string
     */
    public void setupCommand(String str) {
        if (str.equals("help")) {
            if (command != null) {
                helpCommand = command;
            } else {
                helpCommand = "all";
            }
            command = str;
        } else {
            if (command != null) {
                if (command.equals("help")) {
                    helpCommand = str;
                } else {
                    command = str;
                }
            } else {
                command = str;
            }
        }
    }

    /**
     * @param args command list
     * @throws ContactServException *
     */
    public void parseCommandLine(String args[]) throws ContactServException {

        CommandLineParser parser = new PosixParser();

        Options options = new Options();
        Option opt = new Option("g", "gender", true, "gender");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("g", "gender", true, "gender");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "nick", true, "nickname");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("n", "name", true, "full name");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("f", "firstname", true, "first name");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "givenname", true, "given name");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("s", "surname", true, "surname");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("b", "birthday", true, "birthday");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("m", "mailbox", true, "mailbox");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("u", "url", true, "homepage, weblog, workpage or openid");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "image", true, "image");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "phone", true, "phone");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "homepage", true, "homepage");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "weblog", true, "weblog");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "workpage", true, "workpage");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "icq", true, "icq account identifier");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "aim", true, "aim account identifier");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "msn", true, "msn account identifier");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "yahoo", true, "yahoo account identifier");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "jabber", true, "jabber account identifier");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("a", "account", true, "online account");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("o", "openid", true, "openid");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("r", "residence", true, "residence");
        opt.setOptionalArg(true);
        options.addOption(opt);
        opt = new Option("", "friend", true, "friend");
        opt.setOptionalArg(true);
        options.addOption(opt);

        opt = new Option("l", "language", true, "language parameter");
        //opt.setOptionalArg(true);
        options.addOption(opt);

        //String[] targs = new String[] { "real_examples.rdf", "find", "-b",
        //		".*-(12|01|02)-.*", "-u", ".*" };

        try {
            line = parser.parse(options, args);
            /*
               if (line.hasOption("nick")) {
                   String s = line.getOptionValue("nick");
                   System.out.println("nick = " + s);
               }
               if (line.hasOption("birthday")) {
                   String s = line.getOptionValue("birthday");
                   System.out.println("birthday = " + s);
               }
               if (line.hasOption("url")) {
                   String s = line.getOptionValue("url");
                   System.out.println("url = " + s);
               }
               */
            String[] lst = line.getArgs();
            for (String aLst : lst) {
                if (isCommand(aLst)) {
                    setupCommand(aLst);
                } else {
                    if (!inputFileName.equals(DEF_FILENAME)) {
                        System.out.println("Too many data files specified.");
                        System.out.println("   Maybe you should enclose your Regular Expression in single quotes.");
                        throw new ContactServException(127, "");
                    }
                    inputFileName = aLst;
                }
            }
//            System.out.println("command     = " + command);
//            System.out.println("helpCommand = " + helpCommand);
//            System.out.println("input file  = " + inputFileName);
        } catch (ParseException exp) {
            System.out.println("Unexpected exception:" + exp.getMessage());
            throw new ContactServException(127, exp.getMessage());
        }
    }

    /**
     * @throws ContactServException *
     */
    public void dispatch() throws ContactServException {
        if (getCommand() != null) {
            if (getCommand().equals("find")) {
                find();
            } else if (getCommand().equals("get")) {
                get();
            } else if (getCommand().equals("add")) {
                add();
            } else if (getCommand().equals("update")) {
                update();
            } else if (getCommand().equals("remove")) {
                remove();
            } else {    // "help" command
                help();
            }
        } else {
            usage();
            System.out.println("Try `contactserv --help' for more information.");
        }
    }

    /**
     * Searches for contacts by specified field values.
     *
     * @throws ContactServException *
     */
    public void find() throws ContactServException {

        srv.init(inputFileName);
//        List<Contact> contacts = srv.find();
        List<Contact> contacts = srv.find(PropertyPairsMaker.getPropertyPairs(line));

        for (Contact contact : contacts) {
            System.out.println(contact.getUri());
//            System.out.println("Name Con : " + contact.getName());
        }
    }

    /**
     * Displays values of the fields for specified contact.
     *
     * @throws ContactServException *
     */
    public void get() throws ContactServException {
        GetCmdProc cmdProc = new GetCmdProc(srv, PropertyPairsMaker.getPropertyPairs(line));

        srv.init(inputFileName);
        cmdProc.run();
    }

    /**
     * Add field values to the specified contact.
     *
     * @throws ContactServException *
     */
    public void add() throws ContactServException {
        AddCmdProc cmdProc = new AddCmdProc(srv, PropertyPairsMaker.getPropertyPairs(line));

        srv.init(inputFileName);
        cmdProc.run();
    }

    /**
     * Updates specified contact field values.
     *
     * @throws ContactServException *
     */
    public void update() throws ContactServException {
        srv.init(inputFileName);
    }

    /**
     * Removes whole contact(s) with all fields on specified URI(s).
     *
     * @throws ContactServException *
     */
    public void remove() throws ContactServException {
        srv.init(inputFileName);
    }

    /**
     * Prints out the most common help on usage of this service.
     */
    public void usage() {
        System.out.println("contactserv - utility to operate with a specified FOAF file in the rdf/xml format.");
        System.out.println("Usage: contactserv [path...] [[--]help|find|get|add|update|remove|[--]version] [expression]");
//        System.out.println("Try `contactserv --help' for more information.");
//        System.out.println("COMMAND: find - to find contacts' URI(s) corresponding some constraint fields' values.");
//        System.out.println("         get - to display all or specified explicitly contact fields on the specified URI(s).");
//        System.out.println("         add - to add some not duplicating contact fields' values on the specified URI(s).");
//        System.out.println("         update - to update or delete contact fields' values on the specified URI(s).");
//        System.out.println("         remove - to remove whole contacts with all fields on the specified URI(s).");
//        System.out.println("         [--]help or -h - to access the built-in tool documentation.");
//        System.out.println("         [--]version or -v - to see an information about the current tool version.");
    }

    /**
     * Prints help on usage of this service.
     */
    public void help() {
        if (getHelpCommand() == null || getHelpCommand().equals("find")) {
            usage();
            System.out.println("\nCOMMAND: find");
            System.out.println("  --gender          -g    gender                     'male' or 'female'");
            System.out.println("  --nick            none  nick name 	             any regular expression for a literal values");
            System.out.println("  --name            -n    full name 	             any regular expression for a literal values");
            System.out.println("  --firstname       -f    first name 	             any regular expression for a literal values");
            System.out.println("  --surname         -s    surname                    any regular expression for a literal values");
            System.out.println("  --birthday        -b    date of birth              yyyy-mm-dd date format");
            System.out.println("  --mailbox         -m    mailbox                    any regular expression to find an ordinal emails");
            System.out.println("  --url             -u    homepage, weblog,          any regular expression to find web page's URLs");
            System.out.println("                          workpage or openid");
            System.out.println("  --friend          none  friend                     any regular expression to find contact's URIs");
            System.out.println("  --keyword         -k    search by a keyword        any regular expression to find everything 	not used");
        } else if (getHelpCommand().equals("get")) {
            usage();
            System.out.println("\nCOMMAND: get");
            System.out.println("  --gender          -g	  gender                     'male' or 'female'");
            System.out.println("  --nick            none  nick name                  a literal value");
            System.out.println("  --name            -n	  name                       an ordinary name");
            System.out.println("  --firstname       -f	  first name                 a literal value");
            System.out.println("  --surname         -s	  surname                    a literal value");
            System.out.println("  --birthday        -b	  date of birth              see the 'find' command arguments descriptions");
            System.out.println("  --image           -i	  image                      an image URL");
            System.out.println("  --mailbox         -m	  mailbox account            an email address URI");
            System.out.println("  --mailboxsha1sum  none  mailbox SHA1 summary       a literal value");
            System.out.println("  --phone           none  phone                      a telephone URI");
            System.out.println("  --homepage        none  homepage                   a web page URL");
            System.out.println("  --weblog          none  weblog                     a web page URL");
            System.out.println("  --workpage        none  workpage                   a web page URL");
            System.out.println("  --icq             none  ICQ account identifier     a literal value");
            System.out.println("  --aim             none  AIM account identifier     a literal value");
            System.out.println("  --msn             none  MSN account identifier     a literal value");
            System.out.println("  --yahoo           none  Yahoo account identifier   a literal value");
            System.out.println("  --jabber          none  Jabber account identifier  a literal value");
            System.out.println("  --account         -a 	  online account             username@service [ profile ]");
            System.out.println("  --openid          -o 	  openid                     an OpenID profile URL");
            System.out.println("  --residence       -r 	  residence                  WGS84 latitude:longitude");
            System.out.println("  --friend          none  friend                     an other contact URI");
        } else if (getHelpCommand().equals("add")) {
            usage();
            System.out.println("\nCOMMAND: add");
            System.out.println("The command arguments are identical to arguments from the get command, but there are some additional important rules:");
            System.out.println("   1. Duplicating contact field values will be ignored;");
            System.out.println("   2. The command doesn't sensitive to the language argument;");
            System.out.println("   3. It is possible to enter multiple contact field values separated by comma;");
            System.out.println("   4. You cannot add automatically regenerated fields manually: a mailbox SHA1 summary;");
            System.out.println("   5. If some contact fields have not been added explicitly they can be calculated automatically: a name.\n");
            System.out.println("New contact field values should satisfy with the following simple rules:");
            System.out.println("   1. You can add a language code @postfix to a literal value;");
            System.out.println("   2. Literal value that contains comma or '@' symbol should be framed with ', \" or ` symbols for choice.");
        } else if (getHelpCommand().equals("update")) {
            usage();
            System.out.println("\nCOMMAND: update");
            System.out.println("The command arguments are identical to arguments from the get command, but you can update and delete contact fields values instead of only viewing them by means of the following commands:");
            System.out.println("   * To leave the current field value press the 'TAB' button;");
            System.out.println("   * To modify the contact field type a new value for it;");
            System.out.println("   * To delete the contact field value enter an empty value.\n");
            System.out.println("And some important rules exist:");
            System.out.println("   1. Duplicating contact field values will be deleted;");
            System.out.println("   2. You cannot update or delete automatically regenerated fields (see the add command for details).\n");
            System.out.println("New contact fields values should satisfy with the rules described in the add command section.");
        } else if (getHelpCommand().equals("remove")) {
            usage();
            System.out.println("\nCOMMAND: remove");
            System.out.println("No predefined arguments.");
        } else {
            usage();
            System.out.println("\nTo view the description of any command simply write it's name after the 'help' command:");
            System.out.println("contactserv [--]help <command>");
            System.out.println("\nCOMMAND");
            System.out.println("  find   - to find contacts' URI(s) corresponding some constraint field values.");
            System.out.println("  get    - to display all or specified explicitly contact fields on the specified URI(s).");
            System.out.println("  add    - to create a new contact or add contact field values on the specified URI(s).");
            System.out.println("  update - to update or delete contact field values on the specified URI(s).");
            System.out.println("  remove - to remove whole contacts with all fields on the specified URI(s).");
            System.out.println("  [--]help or -h - to access the built-in tool documentation.");
            System.out.println("  [--]version or -v - to see an information about the tool version.");
            System.out.println("  get, add, update and remove are URI-centric commands, they consume URIs consistently.");
            System.out.println("  Sometimes you can use the find command to populate them. To exit from these commands enter an empty URI.");
            System.out.println("\nCOMMAND ARGUMENTS");
            System.out.println("  --gender          -g    gender                     male' or 'female'");
            System.out.println("  --nick            none  nick name 	             any regular expression for a literal values");
            System.out.println("  --name            -n    full name 	             any regular expression for a literal values");
            System.out.println("  --firstname       -f    first name 	             any regular expression for a literal values");
            System.out.println("  --surname         -s    surname                    any regular expression for a literal values");
            System.out.println("  --birthday        -b    date of birth              yyyy-mm-dd date format");
            System.out.println("  --mailbox         -m    mailbox                    any regular expression to find an ordinal emails");
            System.out.println("  --url             -u    homepage, weblog,          any regular expression to find web page's URLs");
            System.out.println("                          workpage or openid");
            System.out.println("  --friend          none  friend                     any regular expression to find contact's URIs");
            System.out.println("  --keyword         -k    search by a keyword 	     any regular expression to find everything 	not used");
            System.out.println("  --image           -i	  image                      an image URL");
            System.out.println("  --mailboxsha1sum  none  mailbox SHA1 summary 	     a literal value");
            System.out.println("  --phone           none  phone                      a telephone URI");
            System.out.println("  --homepage        none  homepage                   a web page URL");
            System.out.println("  --weblog          none  weblog                     a web page URL");
            System.out.println("  --workpage        none  workpage                   a web page URL");
            System.out.println("  --icq             none  ICQ account identifier     a literal value");
            System.out.println("  --aim             none  AIM account identifier     a literal value");
            System.out.println("  --msn             none  MSN account identifier     a literal value");
            System.out.println("  --yahoo           none  Yahoo account identifier   a literal value");
            System.out.println("  --jabber          none  Jabber account identifier  a literal value");
            System.out.println("  --account         -a 	  online account             username@service [ profile ]");
            System.out.println("  --openid          -o 	  openid                     an OpenID profile URL");
            System.out.println("  --residence       -r 	  residence 	             WGS84 latitude:longitude");
            System.out.println("  --language 	    -l 	  language parameter 	     the list of normalized to lowercase language code of language ");
            System.out.println("                                                     tags separated by ',' or 'all' 	 all");
            System.out.println("  --force           none  never display any prompts");
        }
    }

    /**
     * @param args command line parameters
     */
    public static void main(String args[]) {

        ContactServ app = new ContactServ();
        int rc = ContactServException.OK;

        try {
            app.parseCommandLine(args);
            app.dispatch();
        } catch (ContactServException e) {
            rc = e.getRetCode();
        }

        System.exit(rc);
    }
}
